#pragma once

#define LINUX 1

//----------system operation----------
#ifdef LINUX
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#endif
#ifdef WIN32
#include <io.h>
#include <direct.h>
#endif

//-----------stl headers-------------------------
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <stdlib.h>
#include <string.h>

#include <iostream>
#include <vector>

#include <cmath>

// =========================================================
// 以下是一些和数学相关的函数
// =========================================================
// 计算三维向量的模
inline float norm(float x, float y, float z){ return std::sqrt(x*x + y*y + z*z);}



// =========================================================
// 以下是和终端打印相关的一些函数
// =========================================================

// 画一条固定长度的分割线(强迫症福利)
inline void pLine(){ printf("============================================================================\n");}
// 打印一个进度条，默认0到100
inline void consoleProgress(int progress)
{
    static char bar[102] = {0};
    static std::string lable = "|/-\\";
    static int inprogress = -1;
    if (inprogress == progress)
        return;

    int st = progress / 2;
    for (int i = 0; i < st; i++)
        bar[i] = '#';

    bar[st] = 0;

    printf("[%-50s][%d%%][%c]\r", bar, progress, lable[progress % 4]);
    fflush(stdout);

    inprogress = progress;

    if (progress == 100) printf("\n");
}

// 打印一个进度条，可以指定开始和终止序号
inline void consoleProgress(int progress, int begin, int end){
    consoleProgress(100. * (progress - begin) / (end - begin));
}

//=============================================================
// 以下是一些和文件操作相关的函数
//=============================================================

// 文件是否存在
inline bool isExist(std::string path){ return (access(path.c_str(), 0)) == 0;}

// 创建文件夹，存在则不创建
inline bool makeDir(std::string path){
    char DirName[256];
    const char* sPathName = path.c_str();

    strcpy(DirName, sPathName);
    int i, len = strlen(DirName);
    if (DirName[len - 1] != '/')
        strcat(DirName, "/");
    len = strlen(DirName);
    for (i = 1; i < len; i++)
    {
        if (DirName[i] == '/' || DirName[i] == '\\')
        {
            DirName[i] = 0;
            if (access(DirName, 0) != 0) //存在则返回0
            {
                if (mkdir(DirName, 0755) == -1)
                {
                    perror("mkdir   error");
                    return false;
                }
            }
            DirName[i] = '/';
        }
    }

    return true;
}

// 删除文件夹，删除成功返回0
inline int deleteDir(const char *path){
    std::string dirPath = path;
    if (isExist(dirPath)){
        std::string shell_delete_command = "rm -rf " + dirPath;
        return system(shell_delete_command.c_str());
    }else return 0;
}

// 返回文件夹下所有文件的全路径文件名
inline std::vector<std::string> openDir(std::string path){
    if(!isExist(path)) perror( ( "Directory: " + path + " is not exist!").c_str() );
    
    std::vector<std::string> filelist;
    DIR *dir = opendir(path.c_str());
    dirent *ptr;
    while ((ptr = readdir(dir)) != NULL){
        if (ptr->d_name[0] == '.') continue;
        filelist.push_back(path + "/" + std::string(ptr->d_name));
    }
    closedir(dir);
    return filelist;
}

// 返回一个文件夹的父目录
inline std::string getParentDir(std::string path){
    int path_end = path.rfind('/');
    return path.substr(0, path_end);
}

// 返回不带斜杠的文件名
inline std::string getFileName(std::string path){
    std::string fullName = path.substr(path.rfind('/') + 1);
    return fullName.substr(0, fullName.find('.'));
}

// ========================================================
// 以下是和时间相关的一些函数
// ========================================================
#include <ctime>
#include <sys/time.h>
// =================================
// 一个计时器, 接口为:
// ------------------------------------
// Timer t("s"); // 以秒为单位, 从定义时开始计时
// // t.begin(); // 或者从某个地方重新开始计时
// cout << t.end() << endl; // 输出历时
// =================================
class Timer
{
public:
    Timer(std::string format = "ms") : _format(format) 
    { 
        begin(); 
    }
    
    void begin()
    {
        gettimeofday(&t1, NULL);
    }

    std::string end()
    {
        gettimeofday(&t2, NULL);
        double t = TimeDiff();
        if(_format == "ms") return std::to_string(t)+_format;
        else if(_format == "s") return std::to_string(t/1000.0)+_format;
        else
        {
            std::cout << "format of time output is only s/ms!" << std::endl;
            exit(-1);
        }   
    }

private:
    timeval t1, t2;
    std::string _format;
    double TimeDiff()
    {
        double t = (t2.tv_sec - t1.tv_sec) * 1000.0;      // sec to ms
        t += (t2.tv_usec - t1.tv_usec) / 1000.0;   // us to ms
        return t;
    }
};